//
// Created by ych on 2/15/24.
//
#include "parser.h"
#include "generator.h"
#include "../machine/ych_state.h"

#define PARSER_STRING_BUFFER_SIZE 128

#define pushM(p, s) pushR(p,(sizeof p)/(sizeof (unsigned int))-1,s);return True
#define pushV() return True

static void pushR(const T *production, int s, SYNStack *stack) {
    while (s >= 0)pushSYNStack(stack, production[s--]);
}

static void initCState(CState *c_state, YState *y_state) {
    c_state->is_declare_func = False;
    c_state->vm_i_p = 0;
    c_state->vm_i_f_p = YCH_VM_FUNC_OFFSET;
    c_state->vm_int_const_p = 0;
    c_state->vm_float_const_p = 0;
    c_state->vm_c_func_p = 0;
    c_state->func_mem_p = 0;
    c_state->vm_string_const_p = 1;
    c_state->memory = &y_state->memory;
}

void initParser(Parser *parser, YState *y_state) {
    parser->y_state = y_state;
    parser->lexer = &y_state->lexer;
    initCState(&parser->c_state, y_state);
    parser->loop_evn = NULL;
    parser->func_state = NULL;
    parser->func_info = NULL;
    parser->temp_string = NULL;
    initSYNStack(&parser->syn_stack);
    initSEMStack(&parser->sem_stack);
    initSEMStack(&parser->sem_stack_if);
    initSymbols(&parser->symbols);
    if (y_state->mode == YSTATE_INTERACTIVE) {
        loadClib(parser);
        parser->var_list = NULL, parser->func_list = NULL;
    } else {
        parser->current_token = getNextToken(parser->lexer);
    }
}

void freeParser(Parser *parser) {
    parser->y_state = NULL;
    parser->lexer = NULL;
    freeSYNStack(&parser->syn_stack);
    freeSEMStack(&parser->sem_stack);
    freeSEMStack(&parser->sem_stack_if);
    freeSymbols(&parser->symbols);
}

void recordSemantics(Parser *parser) {
    parser->recode.vm_i_p = parser->c_state.vm_i_p;
    parser->recode.vm_i_f_p = parser->c_state.vm_i_f_p;
    parser->recode.vm_mem_p = parser->c_state.vm_mem_p;
}

void rollbackSemantics(Parser *parser) {
    parser->c_state.vm_i_p = parser->recode.vm_i_p;
    parser->c_state.vm_i_f_p = parser->recode.vm_i_f_p;
    parser->c_state.vm_mem_p = parser->recode.vm_mem_p;
    parser->c_state.func_mem_p = 0;
    memset(parser->y_state->memory.VM_I + parser->c_state.vm_i_p, 0,
           sizeof(Instruction) * (YCH_VM_FUNC_OFFSET - parser->c_state.vm_i_p));
    memset(parser->y_state->memory.VM_I + parser->c_state.vm_i_f_p, 0,
           sizeof(Instruction) * (YCH_VM_INSTRUCTION_SIZE - parser->c_state.vm_i_f_p));
    freeToken(&parser->current_token);
    while (!isEmptySYNStack(&parser->syn_stack)) {
        popSYNStack(&parser->syn_stack);
    }
    while (!isEmptySEMStack(&parser->sem_stack)) {
        popSEMStack(&parser->sem_stack);
    }
    while (!isEmptySEMStack(&parser->sem_stack_if)) {
        popSEMStack(&parser->sem_stack_if);
    }
    rollbackSymbols(parser);
}

void stageVar(Parser *parser) {
    VarNode *temp = parser->var_list;
    parser->var_list = malloc(sizeof(VarNode));
    parser->var_list->var_string = strdup(parser->current_token.token_value.string->data);
    parser->var_list->pre = temp;
}

void stageFunc(Parser *parser) {
    FuncNode *temp = parser->func_list;
    parser->func_list = malloc(sizeof(FuncNode));
    parser->func_list->func_string = strdup(parser->current_token.token_value.string->data);
    parser->func_list->pre = temp;
}

void clearStage(Parser *parser) {
    while (parser->var_list) {
        VarNode *temp = parser->var_list->pre;
        free(parser->var_list->var_string);
        free(parser->var_list);
        parser->var_list = temp;
    }
    while (parser->func_list) {
        FuncNode *temp = parser->func_list->pre;
        free(parser->func_list->func_string);
        free(parser->func_list);
        parser->func_list = temp;
    }
}

void rollbackSymbols(Parser *parser) {
    while (parser->var_list) {
        VarNode *temp = parser->var_list->pre;
        deleteKeyVarHashMap(&parser->symbols.var_table, parser->var_list->var_string);
        free(parser->var_list->var_string);
        free(parser->var_list);
        parser->var_list = temp;
    }
    while (parser->func_list) {
        FuncNode *temp = parser->func_list->pre;
        deleteKeyFuncHashMap(&parser->symbols.func_table, parser->var_list->var_string);
        free(parser->func_list->func_string);
        free(parser->func_list);
        parser->func_list = temp;
    }
}

void analyzeParser(Parser *parser) {
    loadClib(parser);
    while (analyzeStatementParser(parser) != PARSER_END);
}

int analyzeStatementParser(Parser *parser) {
    T x;
    Token *token = &parser->current_token;
    if (token->token_type == TK_EOF)return PARSER_END;
    pushSYNStack(&parser->syn_stack, NT_S);
    while (!isEmptySYNStack(&parser->syn_stack)) {
        x = popSYNStack(&parser->syn_stack);
        if (x < FIRST_NT) {
            if (x == token->token_type) {
                freeToken(&parser->current_token);
                parser->current_token = getNextToken(parser->lexer);
            } else {
                throwParser(parser);
                throw(EXCEPTION_SYNTAXILLEGAL);
                return PARSER_ERROR;
            }
        } else if (x < FIRST_ACTION) {
            if (!deduce(x, parser->current_token.token_type, &parser->syn_stack)) {
                throwParser(parser);
                throw(EXCEPTION_SYNTAXILLEGAL);
                return PARSER_ERROR;
            }
        } else {
            if (ac(parser, x)) {
                throw(EXCEPTION_SEMILLEGAL);
                return PARSER_ERROR;
            }
        }
    }
    return PARSER_OK;
}

void throwParser(Parser *parser) {
    char buffer[PARSER_STRING_BUFFER_SIZE];
    Error error;
    error.code = EXCEPTION_SYNTAXILLEGAL;
    toStatementEnd(parser->lexer->reader);
    size_t start_pos = parser->lexer->reader->line_start_pos;
    cutString(&error.info, parser->lexer->reader->file_text.data, start_pos, parser->lexer->reader->pos - start_pos);
    sprintf(buffer, " line %zu:SYNTAX ERROR", parser->lexer->reader->line);
    appendString(&error.info, buffer);
    pushErrorStack(&parser->y_state->errors, error);
}

const T P_S1[] = {NT_DS};
const T P_S2[] = {NT_FS};
const T P_S3[] = {NT_RS};
const T P_S4[] = {';'};
const T P_S5[] = {NT_ES};
const T P_S6[] = {NT_IS};
const T P_S7[] = {NT_WS};
const T P_S8[] = {NT_BS};
const T P_S9[] = {NT_CS};
const T P_DS[] = {TK_VAR, NT_DL, ';'};
const T P_DL[] = {AC_MALLOC_VAR, TK_NAME, NT_DA, NT_DF};
const T P_DA1[] = {'=', NT_DV};
const T P_DA2[] = {AC_SEM_POP};
const T P_NT_DF[] = {',', NT_DL};
const T P_NT_DV1[] = {NT_E10, AC_ASSIGN_FIRST};
const T P_NT_DV2[] = {AC_MAT_START, '{', NT_MAT_V_IN, '}', AC_MAT_END};
const T P_NT_DV3[] = {AC_ARRAY_START, '[', NT_ARRAY_LENGTH, ']', '[', NT_ARRAY, ']', AC_ARRAY_END};
const T P_NT_ARRAY_LENGTH[] = {AC_PUSH_CONST, TK_INT_V, AC_SET_ARRAY_LENGTH};
const T P_NT_ARRAY[] = {NT_E10, AC_ARRAY_VALUE_ASSIGN, NT_ARRAY_F};
const T P_NT_ARRAY_F[] = {',', NT_ARRAY};
const T P_NT_MAT_V_IN[] = {'{', NT_MAT_V_IN_IN, '}', AC_MAT_COUNT_ROW, NT_MAT_V_1_F};
const T P_NT_MAT_V_1_F[] = {',', NT_MAT_V_IN};
const T P_NT_MAT_V_IN_IN[] = {NT_E10, AC_MAT_COUNT_COL, NT_MAT_V_2_F};
const T P_NT_MAT_V_2_F[] = {',', NT_MAT_V_IN_IN};
const T P_NT_FS[] = {TK_FUNCTION, AC_DEF_FUNC_START, TK_NAME, '(', NT_FS_PARAM_LIST, ')', NT_CS,
                     AC_DEF_FUNC_END};
const T P_NT_FS_PARAM_LIST[] = {AC_DEF_COUNT_PARAMS, TK_NAME, NT_FS_PARAM_LIST_F};
const T P_NT_FS_PARAM_LIST_F[] = {',', NT_FS_PARAM_LIST};
const T P_NT_S_LIST[] = {NT_S, NT_S_LIST};
const T P_NT_RS[] = {TK_RETURN, NT_R_F, AC_RETURN, ';'};
const T P_NT_R_F[] = {NT_E10};
const T P_NT_ES[] = {NT_E10, AC_POP, ';'};
const T P_NT_E10[] = {NT_E9, NT_E10_F};
const T P_NT_E10_F[] = {'=', AC_SEM_PUSH_ASSIGN, NT_E9, NT_E10_F};
const T P_NT_E10_F1[] = {AC_ASSIGN_END};
const T P_NT_E9[] = {NT_E8, NT_E9_F};
const T P_NT_E9_F[] = {'|', NT_E8, AC_OR, NT_E9_F};
const T P_NT_E8[] = {NT_E7, NT_E8_F};
const T P_NT_E8_F[] = {'&', NT_E7, AC_AND, NT_E8_F};
const T P_NT_E7[] = {NT_E6};
const T P_NT_E7_1[] = {'!', NT_E7, AC_NOT};
const T P_NT_E6[] = {NT_E5, NT_E6_F};
const T P_NT_E6_F1[] = {TK_EQUAL, NT_E5, AC_EQUAL, NT_E6_F};
const T P_NT_E6_F2[] = {TK_NOTEQUAL, NT_E5, AC_NOTEQUAL, NT_E6_F};
const T P_NT_E5[] = {NT_E4, NT_E5_F};
const T P_NT_E5_F1[] = {'<', NT_E4, AC_LESS, NT_E5_F};
const T P_NT_E5_F2[] = {'>', NT_E4, AC_GREATER, NT_E5_F};
const T P_NT_E5_F3[] = {TK_LESSEQUAL, NT_E4, AC_LESSEQUAL, NT_E5_F};
const T P_NT_E5_F4[] = {TK_GREATEREQUAL, NT_E4, AC_GREATEREQUAL, NT_E5_F};
const T P_NT_E4[] = {NT_E3, NT_E4_F};
const T P_NT_E4_F1[] = {'+', NT_E3, AC_ADD, NT_E4_F};
const T P_NT_E4_F2[] = {'-', NT_E3, AC_SUB, NT_E4_F};
const T P_NT_E3[] = {NT_E2, NT_E3_F};
const T P_NT_E3_F1[] = {'*', NT_E2, AC_MUL, NT_E3_F};
const T P_NT_E3_F2[] = {'/', NT_E2, AC_DIV, NT_E3_F};
const T P_NT_E3_F3[] = {'%', NT_E2, AC_MOD, NT_E3_F};
const T P_NT_E3_F4[] = {TK_INNER, NT_E2, AC_INNER, NT_E3_F};
const T P_NT_E2[] = {NT_E1};
const T P_NT_E2_1[] = {'+', NT_E1};
const T P_NT_E2_2[] = {'-', NT_E1, AC_NEG};
const T P_NT_E1[] = {NT_F, NT_E1_F};
const T P_NT_E1_F[] = {TK_POW, NT_F, AC_POW, NT_E1_F};
const T P_NT_F1[] = {AC_STAGE, TK_NAME, NT_F_F};
const T P_NT_F2[] = {AC_PUSH_CONST, NT_F_CONST};
const T P_NT_F3[] = {'(', NT_E10, ')'};
const T P_NT_F_CONST1[] = {TK_INT_V};
const T P_NT_F_CONST2[] = {TK_FLOAT_V};
const T P_NT_F_CONST3[] = {TK_STRING_V};
const T P_NT_F_CONST4[] = {TK_TRUE};
const T P_NT_F_CONST5[] = {TK_FALSE};
const T P_NT_F_F1[] = {AC_PUSH_VAR, NT_F_F_F};
const T P_NT_F_F2[] = {AC_PUSH_FUNC, '(', NT_F_PARAM_LIST, ')', AC_FUNC_END};
const T P_NT_F_F_F[] = {'[', NT_E10, ']', AC_INDEX, NT_F_F_F};
const T P_NT_F_F_MAT[] = {':', '[', NT_E10, ']', '[', NT_E10, ']', AC_MAT_INDEX};
const T P_NT_F_PARAM_LIST[] = {NT_E10, AC_FUNC_COUNT_PARAM, NT_F_PARAM_LIST_F};
const T P_NT_F_PARAM_LIST_F[] = {',', NT_F_PARAM_LIST};
const T P_NT_IS[] = {TK_IF, '(', NT_E10, ')', AC_IF_JUDGE, NT_S, NT_IS_ELSE};
const T P_NT_IS_ELSE[] = {TK_ELSE, AC_SEM_PUSH_ELSE, NT_S, AC_ELSE_END};
const T P_NT_IS_ELSE1[] = {AC_IF_END};
const T P_NT_WS[] = {TK_WHILE, AC_SEM_PUSH_WHILE, '(', NT_E10, ')', AC_WHILE_JUDGE, NT_S, AC_WHILE_END};
const T P_NT_BS[] = {TK_BREAK, AC_WHILE_BREAK, ';'};
const T P_NT_CS[] = {'{', NT_S_LIST, '}'};

static int deduce(T x, T w, SYNStack *stack) {
    switch (x) {
        case NT_S:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_S5, stack);
                case TK_VAR:
                pushM(P_S1, stack);
                case TK_FUNCTION:
                pushM(P_S2, stack);
                case TK_RETURN:
                pushM(P_S3, stack);
                case TK_IF:
                pushM(P_S6, stack);
                case TK_WHILE:
                pushM(P_S7, stack);
                case TK_BREAK:
                pushM(P_S8, stack);
                case '{':
                pushM(P_S9, stack);
                case ';':
                pushM(P_S4, stack);
                default:
                    return False;
            }
        case NT_DS:
            switch (w) {
                case TK_VAR:
                pushM(P_DS, stack);
                default:
                    return False;
            }
        case NT_DL:
            switch (w) {
                case TK_NAME:
                pushM(P_DL, stack);
                default:
                    return False;
            }
        case NT_DV:
            switch (w) {
                case '[':
                pushM(P_NT_DV3, stack);
                case '{':
                pushM(P_NT_DV2, stack);
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_DV1, stack);
                default:
                    return False;
            }
        case NT_DA:
            switch (w) {
                case '=':
                pushM(P_DA1, stack);
                case ';':
                case ',':
                pushM(P_DA2, stack);
                default:
                    return False;
            }
        case NT_DF:
            switch (w) {
                case ';':
                    pushV();
                case ',':
                pushM(P_NT_DF, stack);
                default:
                    return False;
            }
        case NT_MAT_V_IN:
            switch (w) {
                case '{':
                pushM(P_NT_MAT_V_IN, stack);
                case '}':
                    pushV();
                default:
                    return False;
            }
        case NT_MAT_V_IN_IN:
            switch (w) {
                case '}':
                    pushV();
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_MAT_V_IN_IN, stack);
                default:
                    return False;
            }
        case NT_MAT_V_1_F:
            switch (w) {
                case ',':
                pushM(P_NT_MAT_V_1_F, stack);
                case '}':
                    pushV();
                default:
                    return False;
            }
        case NT_MAT_V_2_F:
            switch (w) {
                case '}':
                    pushV();
                case ',':
                pushM(P_NT_MAT_V_2_F, stack);
                default:
                    return False;
            }
        case NT_FS:
            switch (w) {
                case TK_FUNCTION:
                pushM(P_NT_FS, stack);
                default:
                    return False;
            }
        case NT_FS_PARAM_LIST:
            switch (w) {
                case TK_NAME:
                pushM(P_NT_FS_PARAM_LIST, stack);
                case ')':
                    pushV();
                default:
                    return False;
            }
        case NT_FS_R:
            switch (w) {
                case '{':
                    pushV();
                default:
                    return False;
            }
        case NT_FS_PARAM_LIST_F:
            switch (w) {
                case ')':
                    pushV();
                case ',':
                pushM(P_NT_FS_PARAM_LIST_F, stack);
                default:
                    return False;
            }
        case NT_S_LIST:
            switch (w) {
                case '}':
                    pushV();
                case TK_VAR:
                case TK_RETURN:
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                case ';':
                case TK_IF:
                case TK_WHILE:
                case TK_BREAK:
                pushM(P_NT_S_LIST, stack);
                default:
                    return False;
            }
        case NT_RS:
            switch (w) {
                case TK_RETURN:
                pushM(P_NT_RS, stack);
                default:
                    return False;
            }
        case NT_R_F:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_R_F, stack);
                case ';':
                    pushV();
                default:
                    return False;
            }
        case NT_ES:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_ES, stack);
                default:
                    return False;
            }
        case NT_E10:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_E10, stack);
                default:
                    return False;
            }
        case NT_E10_F:
            switch (w) {
                case ')':
                case ']':
                case '}':
                case ',':
                case ';':
                pushM(P_NT_E10_F1, stack);
                case '=':
                pushM(P_NT_E10_F, stack);
                default:
                    return False;
            }
        case NT_E9:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_E9, stack);
                default:
                    return False;
            }
        case NT_E9_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case '=':
                    pushV();
                case '|':
                pushM(P_NT_E9_F, stack);
                default:
                    return False;
            }
        case NT_E8:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_E8, stack);
                default:
                    return False;
            }
        case NT_E8_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case '|':
                case '=':
                    pushV();
                case '&':
                pushM(P_NT_E8_F, stack);
                default:
                    return False;
            }
        case NT_E7:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E7, stack);
                case '!':
                pushM(P_NT_E7_1, stack);
                default:
                    return False;
            }
        case NT_E6:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E6, stack);
                default:
                    return False;
            }
        case NT_E6_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case '&':
                case '|':
                case '=':
                    pushV();
                case TK_EQUAL:
                pushM(P_NT_E6_F1, stack);
                case TK_NOTEQUAL:
                pushM(P_NT_E6_F2, stack);
                default:
                    return False;
            }
        case NT_E5:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E5, stack);
                default:
                    return False;
            }
        case NT_E5_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case '<':
                pushM(P_NT_E5_F1, stack);
                case '>':
                pushM(P_NT_E5_F2, stack);
                case TK_LESSEQUAL:
                pushM(P_NT_E5_F3, stack);
                case TK_GREATEREQUAL:
                pushM(P_NT_E5_F4, stack);
                default:
                    return False;
            }
        case NT_E4:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E4, stack);
                default:
                    return False;
            }
        case NT_E4_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case '+':
                pushM(P_NT_E4_F1, stack);
                case '-':
                pushM(P_NT_E4_F2, stack);
                default:
                    return False;
            }
        case NT_E3:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                pushM(P_NT_E3, stack);
                default:
                    return False;
            }
        case NT_E3_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case '+':
                case '-':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case '*':
                pushM(P_NT_E3_F1, stack);
                case '/':
                pushM(P_NT_E3_F2, stack);
                case '%':
                pushM(P_NT_E3_F3, stack);
                case TK_INNER:
                pushM(P_NT_E3_F4, stack);
                default:
                    return False;
            }
        case NT_E2:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                pushM(P_NT_E2, stack);
                case '+':
                pushM(P_NT_E2_1, stack);
                case '-':
                pushM(P_NT_E2_2, stack);
                default:
                    return False;
            }
        case NT_E1:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                pushM(P_NT_E1, stack);
                default:
                    return False;
            }
        case NT_E1_F:
            switch (w) {
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case '+':
                case '-':
                case '*':
                case '/':
                case '%':
                case TK_INNER:
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                case TK_POW:
                pushM(P_NT_E1_F, stack);
                default:
                    return False;
            }
        case NT_F:
            switch (w) {
                case TK_NAME:
                pushM(P_NT_F1, stack);
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                pushM(P_NT_F2, stack);
                case '(':
                pushM(P_NT_F3, stack);
                default:
                    return False;
            }
        case NT_F_F:
            switch (w) {
                case '(':
                pushM(P_NT_F_F2, stack);
                case '[':
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case TK_POW:
                case '*':
                case '/':
                case '%':
                case TK_INNER:
                case '+':
                case '-':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                case ':':
                pushM(P_NT_F_F1, stack);
                default:
                    return False;
            }
        case NT_F_F_F:
            switch (w) {
                case '[':
                pushM(P_NT_F_F_F, stack);
                case ':':
                pushM(P_NT_F_F_MAT, stack);
                case ';':
                case ')':
                case ']':
                case '}':
                case ',':
                case TK_POW:
                case '*':
                case '/':
                case '%':
                case TK_INNER:
                case '+':
                case '-':
                case '<':
                case '>':
                case TK_LESSEQUAL:
                case TK_GREATEREQUAL:
                case TK_EQUAL:
                case TK_NOTEQUAL:
                case '&':
                case '|':
                case '=':
                    pushV();
                default:
                    return False;
            }
        case NT_F_PARAM_LIST:
            switch (w) {
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_F_PARAM_LIST, stack);
                case ')':
                    pushV();
                default:
                    return False;
            }
        case NT_F_PARAM_LIST_F:
            switch (w) {
                case ',':
                pushM(P_NT_F_PARAM_LIST_F, stack);
                case ')':
                    pushV();
                default:
                    return False;
            }
        case NT_F_CONST:
            switch (w) {
                case TK_INT_V:
                pushM(P_NT_F_CONST1, stack);
                case TK_FLOAT_V:
                pushM(P_NT_F_CONST2, stack);
                case TK_STRING_V:
                pushM(P_NT_F_CONST3, stack);
                case TK_TRUE:
                pushM(P_NT_F_CONST4, stack);
                case TK_FALSE:
                pushM(P_NT_F_CONST5, stack);
                default:
                    return False;
            }
        case NT_IS:
            switch (w) {
                case TK_IF:
                pushM(P_NT_IS, stack);
                default:
                    return False;
            }
        case NT_IS_ELSE:
            switch (w) {
                case TK_ELSE:
                pushM(P_NT_IS_ELSE, stack);
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                case TK_VAR:
                case TK_FUNCTION:
                case TK_RETURN:
                case TK_IF:
                case TK_WHILE:
                case TK_BREAK:
                case '{':
                case ';':
                case TK_DEL:
                case TK_EOF:
                case '}':
                pushM(P_NT_IS_ELSE1, stack);
                default:
                    return False;
            }
        case NT_WS:
            switch (w) {
                case TK_WHILE:
                pushM(P_NT_WS, stack);
                default:
                    return False;
            }
        case NT_BS:
            switch (w) {
                case TK_BREAK:
                pushM(P_NT_BS, stack);
                default:
                    return False;
            }
        case NT_CS:
            switch (w) {
                case '{':
                pushM(P_NT_CS, stack);
                default:
                    return False;
            }
        case NT_ARRAY:
            switch (w) {
                case ']':
                    pushV();
                case '[':
                case '{':
                case TK_NAME:
                case '(':
                case TK_INT_V:
                case TK_FLOAT_V:
                case TK_STRING_V:
                case TK_TRUE:
                case TK_FALSE:
                case '+':
                case '-':
                case '!':
                pushM(P_NT_ARRAY, stack);
                default:
                    return False;
            }
        case NT_ARRAY_F:
            switch (w) {
                case ',':
                pushM(P_NT_ARRAY_F, stack);
                case ']':
                    pushV();
                default:
                    return False;
            }
        case NT_ARRAY_LENGTH:
            switch (w) {
                case ']':
                    pushV();
                case TK_INT_V:
                pushM(P_NT_ARRAY_LENGTH, stack);
                default:
                    return False;
            }
        default:
            return False;
    }
}